package edu.ucla.whi.wanda;

import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Future;

import org.restlet.data.MediaType;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.Get;

import com.amazonaws.services.simpledb.model.BatchPutAttributesRequest;
import com.amazonaws.services.simpledb.model.CreateDomainRequest;
import com.amazonaws.services.simpledb.model.DeleteDomainRequest;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.amazonaws.services.simpledb.model.ReplaceableItem;
import com.csvreader.CsvReader;

public class ResetResource extends BaseResource {
	private final String[] sdbDomains = {
			SUBJECTS_DOMAIN, 
			SENSORS_DOMAIN,
			MEASUREMENTS_DOMAIN,
			EVENTS_DOMAIN};

	public static final String path = "/reset";
	public static final String description = "Reset the entire database";
	
	
	public ResetResource() {
		super();
		
		initDescribe(path, description, null, MediaType.TEXT_HTML);
	}
	
	private CsvReader makeCsvReader(String file, String[] headers) throws Exception {
		Representation csv = new ClientResource("war:///csv/" + file).get();
		CsvReader reader = new CsvReader(csv.getReader(), ',');
		reader.setHeaders(headers);
		return reader;
	}
	
	private String makeTimestamp(String date) throws Exception {
		SimpleDateFormat format = new SimpleDateFormat("y-M-d H:m:s");
		return "" + (format.parse(date)).getTime();
	}
	
	private void addUsers() throws Exception {
		List<ReplaceableItem> items = new LinkedList<ReplaceableItem>();
		
		CsvReader reader = makeCsvReader("user.csv", new String[]{"id", "name", "gender", "age", "height", "phone"});
		while (reader.readRecord()) {
			ReplaceableItem item = new ReplaceableItem();
			item.setName(reader.get("id"));
			
			List<ReplaceableAttribute> attributes = new LinkedList<ReplaceableAttribute>();
			attributes.add(new ReplaceableAttribute("Name", reader.get("name"), true));
			attributes.add(new ReplaceableAttribute("Gender", reader.get("gender"), true));
			attributes.add(new ReplaceableAttribute("Age", reader.get("age"), true));
			attributes.add(new ReplaceableAttribute("Height", reader.get("height"), true));
			
			item.setAttributes(attributes);
			items.add(item);
			
			if (items.size() > 20) {
				getDB().batchPutAttributes(new BatchPutAttributesRequest(SUBJECTS_DOMAIN, items));
				items.clear();
			}
			
		}

		if (items.size() > 0) {
			getDB().batchPutAttributes(new BatchPutAttributesRequest(SUBJECTS_DOMAIN, items));
		}
	}

	private void addWeights() throws Exception {
		List<ReplaceableItem> items = new LinkedList<ReplaceableItem>();
		
		CsvReader reader = makeCsvReader("weight.csv", new String[]{"user_id", "date", "weight"});
		while (reader.readRecord()) {
			ReplaceableItem item = new ReplaceableItem();
			item.setName(newId());
			
			List<ReplaceableAttribute> attributes = new LinkedList<ReplaceableAttribute>();
			attributes.add(new ReplaceableAttribute("SubjectId", reader.get("user_id"), true));
			attributes.add(new ReplaceableAttribute("SensorId", reader.get("weight"), true));
			attributes.add(new ReplaceableAttribute("StartTime", makeTimestamp(reader.get("date")), true));
			attributes.add(new ReplaceableAttribute("Value", reader.get("height"), true));
			
			item.setAttributes(attributes);
			items.add(item);
			
			if (items.size() > 20) {
				getDB().batchPutAttributes(new BatchPutAttributesRequest(MEASUREMENTS_DOMAIN, items));
				items.clear();
			}
		}
		
		if (items.size() > 0) {
			getDB().batchPutAttributes(new BatchPutAttributesRequest(MEASUREMENTS_DOMAIN, items));
		}
	}

	private ReplaceableItem makeBPItem(String user, String sensor, String timestamp, String value) {
		ReplaceableItem item = new ReplaceableItem();
		item.setName(newId());
		
		List<ReplaceableAttribute> attributes = new LinkedList<ReplaceableAttribute>();
		attributes.add(new ReplaceableAttribute("SubjectId", user, true));
		attributes.add(new ReplaceableAttribute("SensorId", sensor, true));
		attributes.add(new ReplaceableAttribute("StartTime", timestamp, true));
		attributes.add(new ReplaceableAttribute("Value", value, true));
		
		item.setAttributes(attributes);
		return item;
	}
	
	private void addBloodPressures() throws Exception {
		List<ReplaceableItem> items = new LinkedList<ReplaceableItem>();
		
		CsvReader reader = makeCsvReader("bp.csv", new String[]{"user_id", "date", "sys", "dia", "bpm"});
		
		
		while (reader.readRecord()) {
			String timestamp = makeTimestamp(reader.get("date"));
			
			items.add(makeBPItem(reader.get("user_id"), "bp_systolic", timestamp, reader.get("sys")));
			items.add(makeBPItem(reader.get("user_id"), "bp_diastolic", timestamp, reader.get("dia")));
			items.add(makeBPItem(reader.get("user_id"), "pulse", timestamp, reader.get("bpm")));
			
			if (items.size() > 20) {
				getDB().batchPutAttributes(new BatchPutAttributesRequest(MEASUREMENTS_DOMAIN, items));
				items.clear();
			}
		}
		
		if (items.size() > 0) {
			getDB().batchPutAttributes(new BatchPutAttributesRequest(MEASUREMENTS_DOMAIN, items));
		}
	}
	
	
	private void addSensor(String id, String type, String unit) throws Exception {
		List<ReplaceableAttribute> attributes = new LinkedList<ReplaceableAttribute>();
		attributes.add(new ReplaceableAttribute("Type", type, true));
		attributes.add(new ReplaceableAttribute("Unit", unit, true));
		getDB().putAttributes(new PutAttributesRequest(SENSORS_DOMAIN, id, attributes));
	}
	
	private void addSensors() throws Exception {
		addSensor("bp_systolic", "blood pressure", "mmHg");
		addSensor("bp_diastolic", "blood pressure", "mmHg");
		addSensor("pulse", "heart", "bpm");
		addSensor("weight", "weight", "lb");
	}
	
	@Get("html")
	public String Reset() throws Exception {
		StringBuilder ret = new StringBuilder();

		List<Future<Void>> tasks = new LinkedList<Future<Void>>();
		
		// clear SimpleDB
        for (String domain : getDB().listDomains().getDomainNames()) {
        	tasks.add(getDB().deleteDomainAsync(new DeleteDomainRequest(domain)));
        	ret.append("Removed SimpleDB domain: " + domain + "\n");
        }

        for (Future<Void> task : tasks) {
    		task.get();
        }
        
        // re-create domains
        tasks.clear();
        for (String domain : sdbDomains) {
        	tasks.add(getDB().createDomainAsync(new CreateDomainRequest(domain)));
        	ret.append("Created SimpleDB domain: " + domain + "\n");
        }

        for (Future<Void> task : tasks) {
    		task.get();
        }

		addUsers();
		addSensors();
		addBloodPressures();
		addWeights();
        
        ret.append("Done");
        
		return ret.toString();
	}
}